#ifndef ACTION_H
#define ACTION_H

/*!
 * \file      action.h
 * \brief     Action of any type.
 * \author    Duriez Franck
 * \version   0.5
 */

#include "assert_macros.h"
#include <exception>

/*!
 * \namespace ActionException
 * \brief     All Exceptions related to Action.
 */
namespace ActionException /*{{{*/
{
	/*!
	 * \class ModifyingConstAction
	 * \brief This happen when a constant Action try to be modified.
	 */
	class ModifyingConstAction : std::exception /*{{{*/
	{
		ModifyingConstAction(std::string what) throw() : /*{{{*/
		m_what(what)
		{
		} /*}}}*/

		virtual ~ModifyingConstAction() throw() /*{{{*/
		{
		} /*}}}*/

		const char* what() const throw() /*{{{*/
		{
			return m_what.data();
		} /*}}}*/

	private:
		std::string m_what;
	}; /*}}}*/
}; /*}}}*/

/*!
 * \class Action
 * \brief This class manage actions.
 *
 * This class manage the infinitesimal parts of an action.
 *
 * \tparam T Class of the action's owner
 */

template < class T >
class Action /*{{{*/
{
public:
	/*!
	 * \brief Contructor.
	 * \param startingprocess : Pointer to the function to execute at the beginning of the action
	 * \param process         : Pointer to the function to execute during the action
	 * \param stoppingprocess : Pointer to the function to execute at the end of the action
	 * \param parent          : Instance of T which is owning the action
	 * \param constant        : Can this Action be modified ?
	 */
	Action(void (T::*startingprocess)(), void (T::*process)(),
	       void (T::*stoppingprocess)(),
	       T * parent, bool constant = true);

	/*!
	 * \brief Copy contructor.
	 * \param action : Action to copy
	 */
	Action(Action<T>& action);

	/*!
	 * \deprecated You'd better to use Action::restart
	 * \brief Start the action.
	 *
	 * This function brutally stop the action if in process and start it again. It's
	 * safe but brutal ! Don't use it for continuous Actions.
	 * Use rather Action::restart in this case unless you know what you do.
	 */
	void start();

	/*!
	 * \brief Restart the action
	 * \param useStoppingProcess : Do I use stoppingprocess to end the previous loop ?
	 *
	 * With this function you can choose the RAZ mode contrary to Action::start.
	 * If useStoppingProcess is set to false, the statement of the action is not
	 * changed before a new loop. So it can be dangerous if the Action statements
	 * doesn't converge for any initial condition.
	 */
	void restart(bool useStoppingProcess = true);

	/*!
	 * \brief Stop the action.
	 * \param useStoppingProcess : Do I use stoppingprocess to end the previous loop ?
	 *
	 * This function stop the Action.
	 * If you want to be sure that the Action is in a good statement after stopping it,
	 * choose true for useStoppingProcess.
	 */
	void stop(bool useStoppingProcess = true);

	/*!
	 * \brief Is the action processing ?
	 */
	bool isProcessing() const;

	/*!
	 * \brief Return a description of the action
	 *
	 * Describe the statements of the atttributes.
	 */
	std::string toString() const;

	/*!
	 * \brief Declare that the action is not finished
	 *
	 * You need to use it in the T::process to explicitly inform
	 * that the Action is not finished after one loop of process
	 * otherwise the Action will stop by itself.
	 */
	void maintain();

	/*!
	 * \brief Update the object continously
	 *
	 * You need to call it in the T::update otherwise nothing will
	 * happen !
	 */
	void update();

private:
	// How do this kind of thing ?
	//template<class T> friend class T;
	//friend void T::maintain(T::Action action);

private:
	bool m_on_start; ///< Is starting ?
	bool m_on_process; ///< Is prossessing ?
	bool m_on_stop; ///< Is stopping ?
	bool m_const; /// Can this action be modified ?

	/*!
	 * \brief What to do on starting
	 *
	 * Use it to do preprocessing on your T object.
	 * For example, to be sure that the object is in
	 * a right configuration.
	 */
	void (T::*m_startingprocess)();

	/*!
	 * \brief What to do on process
	 *
	 * Use it to explain what the action have to do during a dt
	 * part of time. In this function, use need to use Action::maintain
	 * somewhere to indicate when the action is not finished.
	 * This is implemented in this way for security reasons.
	 */
	void (T::*m_process)();

	/*!
	 * \brief What to do on stopping
	 *
	 * Use it to do postprocessing on your T object.
	 * For example, to check that the job has been
	 * correctly done.
	 */
	void (T::*m_stoppingprocess)();

	T* m_parent; ///< The owner of the action
}; /*}}}*/

#include <action.cpp>

#endif // ACTION_H
